#include <nemesis.Semaphore.h>
#include <nemesis.Thread.h>
#include <nemesis.Runnable.h>
#include <nemesis.Logger.h>
#include <nemesis.TraceWriter.h>
#include <nemesis.Mutex.h>
#include <nemesis.Guard.h>

using namespace std;
using namespace nemesis;

Semaphore g_semaphore (0);

class Producer : public Runnable {
public:
   Producer () : Runnable ("Producer") {;}

private:
   void run () throw (RuntimeException);
};

class Consumer : public Runnable {
public:
   Consumer () : Runnable ("Consumer") {;}

private:
   void run () throw (RuntimeException);
};

int main ()
{
   Producer producer;
   Consumer consumer1;
   Consumer consumer2;

   Thread t1, t2, t3;

   Logger::setLevel (Logger::Debug);
   Logger::initialize ("semaphore", new TraceWriter ("file.trace", 2048000));

   t1.start (producer);
   t2.start (consumer1);
   t3.start (consumer2);

   Logger::debug ("Join", FILE_LOCATION);

   while (t1.isRunning () || t2.isRunning () || t3.isRunning ());
}

void Producer::run () 
   throw (RuntimeException) 
{
   Logger::debug ("Esperando", FILE_LOCATION);
   nemesis::functions::sleep (2000);
   g_semaphore.signal ();
   Logger::debug ("Produce", FILE_LOCATION);

   Logger::debug ("Esperando", FILE_LOCATION);
   nemesis::functions::sleep (2000);
   g_semaphore.signal ();
   Logger::debug ("Produce", FILE_LOCATION);
}

void Consumer::run () 
   throw (RuntimeException) 
{
   g_semaphore.wait ();
   Logger::debug ("Consume", FILE_LOCATION);
}

